Skip to content

feat: OneDrive and Local Folder sync providers + Google Drive re-auth overhaul - #250

Merged
Gnathonic merged 68 commits into
developfrom
feat/filesystem-provider
Jul 6, 2026
Merged

feat: OneDrive and Local Folder sync providers + Google Drive re-auth overhaul#250
Gnathonic merged 68 commits into
developfrom
feat/filesystem-provider

Conversation

@Gnathonic

@Gnathonic Gnathonic commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Summary

Two new sync providers hardened to parity with Drive/MEGA/WebDAV, cross-provider sync fixes, an overhaul of the Google Drive re-auth UX, and removal of the unshipped libraries feature.

New providers

  • OneDrive — MSAL redirect auth + Microsoft Graph. Chunked upload sessions with retry/resume via nextExpectedRanges, per-chunk timeouts, typed ProviderError classification (401 flips the reconnect UI), folder-creation mutex with 409 tolerance, removeDirectoryIfEmpty, logout/init-error hardening.
  • Local Folder — File System Access API (Chromium-only, feature-detected). Typed NOT_FOUND / PERMISSION_REVOKED errors drive the reconnect UI, dead-handle recovery (deleted/moved folders), idempotent copy-then-delete renames, removeDirectoryIfEmpty.

Cross-provider fixes

  • Shared isSyncableFile module replaces six divergent per-provider copies; jpg/jpeg sidecars now accepted on the new providers (previously silently dropped).
  • CloudView gates Sync/Backup/Profile actions on reconnect states (matching the WebDAV read-only gate); shared provider display labels; OneDrive option hidden unless VITE_ONEDRIVE_CLIENT_ID is configured.

Google Drive re-auth overhaul

  • Fixes a cross-device progress clobber: with an expired token, the startup pull was skipped and nothing synced after re-auth, so one page turn on a stale device out-timestamped and overwrote the other device's position. Any reconnect now immediately pulls cloud state (fetchAllCloudVolumes + syncProgress).
  • Reconnect is requested at the moments that matter — app open, opening a book, or the next click after a blocked popup — one click on Google's account chooser, no browser popup-permission setup. Closing the chooser = keep reading unsynced.
  • GIS error_callback registered (blocked popups previously failed silently); NavBar shows a red Reconnect pill when the session is expired.

Removed: unshipped libraries feature (−2,300 LOC)

  • The read-only WebDAV "libraries" feature (never specced, routes already redirected to catalog) is deleted end-to-end: store, views, modals, cache manager, WebDAV client, placeholders, download-queue branches, libraries.json sync plumbing, and the libraryId metadata field.
  • The cloud-OCR-upgrade queue it hosted (used by cloud placeholders) survives, extracted to src/lib/catalog/cloud-ocr-upgrade.ts.
  • Stale #/libraries bookmarks fall back to catalog; stale libraries.json files in cloud folders are ignored.

UI

  • OneDrive listed above WebDAV; WebDAV card mentions Mokuro-Bunko; "Persistent login" copy unified across MEGA/WebDAV/OneDrive.

Config

  • VITE_ONEDRIVE_CLIENT_ID (optional): Azure AD app with the deploy origin as an SPA redirect URI. Documented in README/CLAUDE.md; .env.example added. When unset, the OneDrive option is hidden.

Testing

  • 932 unit tests passing (72 files), svelte-check 0 errors, lint clean, production build OK.
  • Beta-testing on mobile via develop.

🤖 Generated with Claude Code

Gnathonic and others added 30 commits April 23, 2026 12:24
Add design doc for a File System Access API backed sync provider. Feature-gated
on Chromium browsers; handle persisted in a dedicated IndexedDB database owned
by the provider module.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add filesystemCore stub to cloud-provider-core-registry (never called
  at runtime since FilesystemProvider.supportsWorkerDownload = false)
- Widen VolumeMetadata.cloudProvider from narrow literal union to
  ProviderType, fixing cascading errors in cloud-fields.ts,
  library-placeholders.ts, and download-queue.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
processDownload previously only handled supportsWorkerDownload=true. For the
filesystem provider (which sets that to false), downloads were silently
skipped — the queue item stayed in 'downloading' state forever and blocked
all subsequent items. Add a main-thread branch that downloads via the
provider's downloadFile method, extracts the CBZ with @zip.js/zip.js, and
reuses the existing downloadSidecarEntries + processVolumeData pipeline.
The regex on error.message did not match Chrome's DOMException.message
(which does not contain the string 'NotFoundError'), causing spurious
DELETE_FAILED errors when a series folder was already gone during sync.
…ders

The filesystem provider cannot upload from a worker because a
FileSystemDirectoryHandle is bound to the window that received it via
showDirectoryPicker — structured-cloning it to a worker does not carry the
user-granted permission. Introduce a supportsWorkerUpload flag on SyncProvider
(parallel to the existing supportsWorkerDownload) and, when a provider opts
out, compress + upload the archive and any sidecars on the main thread via
provider.uploadFile. Worker-capable providers (Google Drive, MEGA, WebDAV)
are unaffected.
Previous fix bypassed the pool entirely and ran compression + upload on the
main thread for filesystem. With a parallel queue that meant N volumes could
load, compress, and buffer simultaneously with no shared-memory accounting
and no provider concurrency cap.

Instead, submit the same pool task used for real providers but in the worker's
'null provider' compress-only mode. The worker still does the CPU-heavy
compression (throttled by WorkerPool + sharedMemoryManager); the main-thread
onComplete then performs the single filesystem write via provider.uploadFile
while the task's memory reservation is still held. Sidecars follow the same
path. Worker-upload providers (Drive, MEGA, WebDAV) are unchanged.
Previous fix bypassed the pool and did blob read + decompression + processing
on the main thread for filesystem. Even with the queue being serial that
blocks the UI during decompression and leaves memory untracked by the shared
memory manager.

Instead, use the worker's existing decompress-only mode: prepareData reads
the blob on the main thread (required — FileSystemDirectoryHandle is bound to
the window) and passes it to the worker, which decompresses and returns
entries. Memory reservation, provider concurrency gating, and shared memory
tracking all apply uniformly with the existing worker-download path.
Adds design for a fourth real sync provider using Microsoft Graph API via
MSAL.js. Multi-tenant (common) auth covers personal + work/school accounts.
Worker-capable core follows the Drive/WebDAV pattern so WorkerPool throttling
applies uniformly.
Gnathonic and others added 21 commits June 2, 2026 16:21
renameFolder copied files to the new path then recursively deleted the old
folder. When the new path nested under the old one (e.g. a free-text rename
of "Series" to "Series/Archive"), the recursive delete destroyed the files
just written into the subfolder. Skip the cleanup when the new path nests
under the old folder.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The catalog's providerNames map was missing the two new providers, so their
placeholder breakdowns rendered the raw keys ("2 filesystem") instead of
friendly labels. Add Local Folder / OneDrive entries.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ovider

# Conflicts:
#	src/lib/views/CloudView.svelte
…ovider

# Conflicts:
#	src/lib/util/sync/providers/mega/mega-provider.ts
@vercel

vercel Bot commented Jul 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
mokuro-reader Ready Ready Preview, Comment Jul 6, 2026 2:55am

Request Review

@Gnathonic
Gnathonic merged commit 40d1a06 into develop Jul 6, 2026
9 checks passed
@Gnathonic
Gnathonic deleted the feat/filesystem-provider branch July 6, 2026 03:57
adrian-tompkins pushed a commit to adrian-tompkins/mokuro-reader that referenced this pull request Aug 2, 2026
…tbox

fix: Extend hotkey filtering to OCR textboxes and nav keys
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant